﻿using EndpointManagement;
using IM.Easy.Api.AccountManage;
using IM.Easy.Core.AppContext;
using IM.Easy.Core.Extensions;
using IM.Easy.Core.Utils;
using IM.Easy.Entity.Log;
using IM.Easy.LogServices.IServices;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;
using System.Text.Encodings.Web;
using System.Text.Json;

namespace IM.Easy.Api.Filters
{
    /// <summary>
    /// 全局日志记录   -----只记录跟踪日志
    /// </summary>
    public class GlobalLoggerFilter : ActionFilterAttribute
    {
        private IRequestTrackingService _requestTrackingService;
        private Stopwatch _stopwatch;
        private JsonSerializerOptions serializerOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,  // 设置为驼峰命名
            WriteIndented = true, // 如果需要格式化输出，可以设置为 true
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
        };
        public GlobalLoggerFilter(IRequestTrackingService requestTrackingService)
        {
            _requestTrackingService = requestTrackingService;
        }
        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            _stopwatch = Stopwatch.StartNew();

            bool isTrack = false;
            string routePattern = string.Empty;
            string httpMethod = context.HttpContext.Request.Method;

            var endpoint = context.HttpContext.GetEndpoint() as RouteEndpoint;
            routePattern = endpoint.RoutePattern.RawText;
            var api = EndPointManager.Get($"{routePattern}:{httpMethod}") ?? new Entity.System.ApiPermissions();
            isTrack = api.IsTrack;

            if (isTrack)
            {
                var logInfo = CreateLogInfo(context);
                logInfo.ActionName = api.Name;
                logInfo.EndpointId = api.Id;

                var resultContext = await next();
                _stopwatch.Stop();

                UpdateLogInfoWithResponse(logInfo, resultContext);
                _requestTrackingService.InsertAsync(logInfo);
            }
            else
            {
                await next();
            }

        }

        private RequestTrackingLog CreateLogInfo(ActionExecutingContext context)
        {
            var clientIP = context.HttpContext.GetClientUserIp();
            var fullUrl = context.HttpContext.Request.GetDisplayUrl();
            var request = context.HttpContext.Request;
            var actionName = context.ActionDescriptor.DisplayName;
            var terminal = context.HttpContext.GetTerminal();
            var method = request.Method;

            string argumentsJson = argumentsJson = JsonSerializer.Serialize(context.ActionArguments, serializerOptions);

            return new RequestTrackingLog()
            {
                TraceIdentifier = context.HttpContext.TraceIdentifier,
                RequestTime = DateTime.Now,
                Url = fullUrl,
                Arguments = argumentsJson,
                HttpMethod = method,
                UserAgent = context.HttpContext.GetUserAgent(),
                UserId = ImApp.User.Id,
                UserName = ImApp.User.UserName,
                ClientIP = clientIP,
                Terminal = terminal,
            };
        }

        private void UpdateLogInfoWithResponse(RequestTrackingLog logInfo, ActionExecutedContext resultContext)
        {
            logInfo.Duration = _stopwatch.ElapsedMilliseconds;
            logInfo.ResponseTime = DateTime.Now;

            string responseBodyJson = string.Empty;
            if (resultContext.Result is ObjectResult objectResult)
            {
                responseBodyJson = JsonSerializer.Serialize(objectResult.Value, serializerOptions);
            }
            logInfo.ResponseBody = responseBodyJson;
            logInfo.Success = resultContext.Exception == null;
        }
    }
}
